////////////////////////////////////////////////////////////////////////////////
//                                                                            //
//  Filename:    TeaCupDragonGuts.cpp										  //
//  Developer:																  //	
//  Create date:                                                              //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////
//                                                                            //
//  Description: This is the class implementation for the slot gut of the     //
//               Australian Slot machine called Tea Cup Dragon.		          //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////
//        2010 - Riplife Gaming.  All rights reserved.						  //
////////////////////////////////////////////////////////////////////////////////

#include "TeaCupDragonGuts.h"
#include "slotconn.h"
#include "sltsql.h"

// Minimum bet for Tea Cup Dragon: 25 cents. All payouts in the database are calculated with a 25 cents bet
#define minimumBetTCD 25


////////////////////////////////////////////////////////////////////////////
/// TeaCupDragonGuts::m_aScatterWinSpinResults
///
/// This array is used to quickly get the SpinResult for the number of
/// icons.  It is indexed by wheel icon and then count.  So to get the
/// SpinResult for 5 Scatter, use the following code snippet:
///
///		SpinResult result = m_aLineWinSpinResults[ ICON_SCATTER ][ 5 ];
///
/// In this example result would be set to EVT_FIVE_SCATTER.
////////////////////////////////////////////////////////////////////////////
TeaCupDragonGuts::SpinResult TeaCupDragonGuts::m_aScatterWinSpinResults[][6] = 
{
// Number of icons:			0			1				2						3					4					5
/* ICON_WILD */			{	EVT_LOSER,	EVT_LOSER,		EVT_LOSER,				EVT_LOSER,			EVT_LOSER,			EVT_LOSER			},
/* ICON_DRAGON1 */		{	EVT_LOSER,	EVT_LOSER,		EVT_LOSER,				EVT_THREE_DRAGON1,	EVT_FOUR_DRAGON1,	EVT_FIVE_DRAGON1	},
/* ICON_DRAGON2 */		{	EVT_LOSER,	EVT_LOSER,		EVT_LOSER,				EVT_THREE_DRAGON2,	EVT_FOUR_DRAGON2,	EVT_FIVE_DRAGON2	},
/* ICON_DRAGON3 */		{	EVT_LOSER,	EVT_LOSER,		EVT_LOSER,				EVT_THREE_DRAGON3,	EVT_FOUR_DRAGON3,	EVT_FIVE_DRAGON3	},
/* ICON_MONEY */		{	EVT_LOSER,	EVT_LOSER,		EVT_LOSER,				EVT_THREE_MONEY,	EVT_FOUR_MONEY,		EVT_FIVE_MONEY		},
/* ICON_ACE */			{	EVT_LOSER,	EVT_LOSER,		EVT_LOSER,				EVT_THREE_ACE,		EVT_FOUR_ACE,		EVT_FIVE_ACE		},
/* ICON_KING */			{	EVT_LOSER,	EVT_LOSER,		EVT_LOSER,				EVT_THREE_KING,		EVT_FOUR_KING,		EVT_FIVE_KING		},
/* ICON_QUEEN */		{	EVT_LOSER,	EVT_LOSER,		EVT_LOSER,				EVT_THREE_QUEEN,	EVT_FOUR_QUEEN,		EVT_FIVE_QUEEN		},
/* ICON_JACK */			{	EVT_LOSER,	EVT_LOSER,		EVT_LOSER,				EVT_THREE_JACK,		EVT_FOUR_JACK,		EVT_FIVE_JACK		},
/* ICON_TEN */			{	EVT_LOSER,	EVT_LOSER,		EVT_LOSER,				EVT_THREE_TEN,		EVT_FOUR_TEN,		EVT_FIVE_TEN		},
/* ICON_NINE */			{	EVT_LOSER,	EVT_LOSER,		EVT_LOSER,				EVT_THREE_NINE,		EVT_FOUR_NINE,		EVT_FIVE_NINE		},
/* ICON_SCATTER */		{	EVT_LOSER,	EVT_LOSER,		EVT_SCATTER_NEAR_MISS,	EVT_THREE_SCATTER,	EVT_FOUR_SCATTER,	EVT_FIVE_SCATTER	}
};


////////////////////////////////////////////////////////////////////////////
/// @fn 	 TeaCupDragonGuts::TeaCupDragonGuts()   
///
/// This is the default constructor for the class.
////////////////////////////////////////////////////////////////////////////
TeaCupDragonGuts::TeaCupDragonGuts()
{
	// If this doesn't compile it means that someone probably added
	// another icon type but did not update the
	// m_aScatterWinSpinResults array. 
	C_ASSERT( countof( m_aScatterWinSpinResults ) == NUM_VALID_ICONS );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 TeaCupDragonGuts::~TeaCupDragonGuts()
///
/// Destructor for TeaCupDragonGuts. 
////////////////////////////////////////////////////////////////////////////
TeaCupDragonGuts::~TeaCupDragonGuts()
{
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 TeaCupDragonGuts::classifyResult()
///
/// classifyResult for TeaCupDragonGuts. Redefined because this is an all pays
/// slot, we can't use the general one
////////////////////////////////////////////////////////////////////////////
void TeaCupDragonGuts::classifyResult(SlotSpin *spin)
{
    // Classify any scatter pays (implemented as a null function in the base)
	spin->clearScatters();
	
	classifyAllPays(spin);
	classifyScatters(spin);

    // Generate the wheel view for reporting
    storeWheelView(spin);
}

////////////////////////////////////////////////////////////////////////////
/// @fn		TeaCupDragonGuts::tryForJackpot()
///
///	This function tries to win the jackpot and adds the scatter if we hit
/// the jackpot.
////////////////////////////////////////////////////////////////////////////
void TeaCupDragonGuts::tryForJackpot( SlotSpin* spin )
{
	// If we are in the first paid spin (NOT a bonus spin)...
	if ( getGameModeId() == MODE_NORMAL ) 
	{
		// then try for the Random Progressive Jackpot
		// If we hit the jackpot...
		// In an all pays slot, numlines = 1
		if ( getRandomProgressiveJackpotResult( 1 ) ||
			m_bForceRandomJackpot)		{
			// then add a jackpot scatter to the spin.
			spin->addScatter( 0,
				getPayout( EVT_RANDOM_PROGRESSIVE_WINNER )->payoutAmount, 1,
				true, EVT_RANDOM_PROGRESSIVE_WINNER, 0 );
		}
    }

	// In third party games (API) we include the jackpot in every spin so that they can update it.
	// If no jackpot, they have not won the jackpot
	setJackpotAmount( getProgressiveValue() );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 TeaCupDragonGuts::getScatterWinResult()   
///
/// @param   spin				The current spin object.
/// @param   testIcon			The scatter icon that we are searching for.
/// @param   scatterPositions	The bit mask for the scatters positions that we find.
///
/// @return	 SpinResult			A payout from the SpinResult enumeration.
///
/// This helper method is used to evaluate the spin for scatters.
////////////////////////////////////////////////////////////////////////////
TeaCupDragonGuts::SpinResult TeaCupDragonGuts::getScatterWinResult( SlotSpin* spin, uint8 testIcon, int32& scatterPositions ) const
{
	// Declare a local variable to keep up with the icon count.
	uint8 numScatterIcons = 0;

	// Initialize the scatterPositions.
	scatterPositions = 0;

	// Loop through each reel.
  	for( int reel = 0; reel < getReelCount(); reel++ )
	{
		// The position bit for the current icon in case it needs to be stored in a mask.
		uint8 position = reel;

		// Loop through each row in the wheel house.
		for( int row = 0; row < 3; row++ )
		{
			// Get the current stop.
			uint8 stop = relativeWheelPosition( getGameModeId(), reel,
				spin->getStops()[ reel ], row );

			// Get the icon for the current stop.
			uint8 currentIcon = getIcon( getGameModeId(), reel, stop )->iconid;
			
			// If the icon is the one we are looking for...
			if ( currentIcon == testIcon )
			{
				// then increase the icon count
				numScatterIcons++;

				// Set the bit in the position mask for this stop.
				scatterPositions |= 1 << position;
			}

			// Move to the next bit in the position mask.
            position += 5;
		}
	}

	// Use the array to look up the spin result for numScatterIcons.
	return lookupScatterWinSpinResult( testIcon, numScatterIcons );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 TeaCupDragonGuts::evaluateScatterWin()
///
/// This function determines if the current spin wins a scatter payment and
/// adds the scatter.
////////////////////////////////////////////////////////////////////////////
void TeaCupDragonGuts::evaluateScatterWin( SlotSpin* spin, SpinResult srScatterResult, int32 scatterPositions )
{
	// If we got the scatter win (or almost got it)
	if ( srScatterResult != EVT_LOSER )
	{
		// Initialize our multiplier for scatters.
		int32 multiplier = 1;
		
		// Get the base payout for the scatter.
		int32 nPayout = getPayout( srScatterResult )->payoutAmount;

		// Add the payout (with multiplier and bet per line) to the total win for this spin. getBetPerLine()=total bet (because it is an all pays slot)
		increaseTotalWin( nPayout * (getBetPerLine()/minimumBetTCD) );
    
		// If we have more than three scatters, free spins awarded
		int nFreeSpinsAwarded = 0;
		if (srScatterResult == EVT_THREE_SCATTER ||  srScatterResult == EVT_FOUR_SCATTER || srScatterResult == EVT_FIVE_SCATTER)
		{
			nFreeSpinsAwarded = 15;
		}

		// Add a scatter to the spin.
		spin->addScatter( scatterPositions, nPayout * (getBetPerLine()/minimumBetTCD), multiplier, false, srScatterResult, nFreeSpinsAwarded );
	}
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 TeaCupDragonGuts::classifyScatters( SlotSpin* spin )
///
/// @param   spin       Pointer to the spin with stop data.
///
/// This is an override of the framework method.  
/// It determines if the current spin merits free spins or scatter payments.
////////////////////////////////////////////////////////////////////////////
void TeaCupDragonGuts::classifyScatters( SlotSpin* spin )
{	
	// Try for the Random Progressive Jackpot
	tryForJackpot( spin );

	// Declare a local variable to track the scatter positions.
	int32 nScatterPositions = 0;

	// See if there is a scatter.
	SpinResult srResult = getScatterWinResult( spin, ICON_SCATTER, nScatterPositions );

	// Add the scatter, if any.
	evaluateScatterWin( spin, srResult, nScatterPositions );

	//  If three or more scatters, activate free spins
	if (srResult == EVT_THREE_SCATTER ||  srResult == EVT_FOUR_SCATTER || srResult == EVT_FIVE_SCATTER)
	{
		if (getFreeSpins() == 0)
		{
			m_subGame->update( SGIDX_BONUS_GAME_STATE, pfgTriggered );  // Start Free Spins (the user has to choose a dragon)
		}
		else
		{
			m_subGame->update( SGIDX_BONUS_GAME_STATE, pfgReTriggered );  // Increment Free Spins
		}
		incrementFreeSpins( 15 );
		setGameModeId( MODE_FREE_SPIN );
	}
	else
	{
		m_subGame->update( SGIDX_BONUS_GAME_STATE, pfgNone );  
	}
	
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 TeaCupDragonGuts::classifyAllPays( SlotSpin* spin )			  
///
/// @param   spin       Pointer to the spin with stop data.
///
/// This is an override of the framework method.  
/// It determines if the current spin merits free spins or scatter payments.
////////////////////////////////////////////////////////////////////////////
void TeaCupDragonGuts::classifyAllPays( SlotSpin* spin )
{	
	ALL_PAYS_PAYOUT pRow[3];
	uint8 stop, icon;

	// Loop through each first row icon.
	for ( int firstRow = 0; firstRow < 3; firstRow++ )
	{
		stop = relativeWheelPosition( getGameModeId(), 0, spin->getStops()[0], firstRow );
		pRow[firstRow].Icon = getIcon( getGameModeId(), 0, stop )->iconid;
		pRow[firstRow].Positions =  1 << (firstRow*5);
		pRow[firstRow].WinType = EVT_LOSER;
		pRow[firstRow].Multiplier = 1;	
		
		bool8 bContinueReels = true;

  		// Loop through each reel
		for( int reel = 1; reel < getReelCount() && bContinueReels; reel++ )
		{
			// The position bit for the current icon in case it needs to be stored in a mask.
			uint8 position = reel;
			uint8 nMatches = 0;

			for (int row = 0; row < 3; row++ )
			{	
				// Get current icon
				stop = relativeWheelPosition( getGameModeId(), reel, spin->getStops()[reel], row );
				icon = getIcon( getGameModeId(), reel, stop )->iconid;
		
				// We are not looking for scatters here (they are calculated in classifyScatters function)
				if (pRow[firstRow].Icon != ICON_SCATTER)
				{
					if (pRow[firstRow].Icon == ICON_WILD)
					{
						pRow[firstRow].Icon = icon;
						pRow[firstRow].Positions |= 1 << position;
						nMatches++;
					}
					else if (pRow[firstRow].Icon == icon)
					{
						pRow[firstRow].Positions |= 1 << position;
						nMatches++;
					}
					else if (icon == ICON_WILD)
					{
						pRow[firstRow].Positions |= 1 << position;
						nMatches++;
					}

					// Move to the next bit in the position mask
					position += 5;
				}
			}

			if (nMatches == 0)
			{
				// If we did not find the symbol in this reel, stop looking for it
				bContinueReels = false;
			}
			else
			{
				// If we found the symbol in this reel, continue looking for it
				pRow[firstRow].WinType = lookupScatterWinSpinResult( pRow[firstRow].Icon, reel+1 );
				// If the symbol was found twice on this reel (it happens if there is a wild and a symbol), we increment the multiplier
				if (nMatches > 1)
					pRow[firstRow].Multiplier = pRow[firstRow].Multiplier * nMatches;
			}
		}
	}

	// Add the payouts, if any
	for ( int firstRow = 0; firstRow < 3; firstRow++ )
	{
		if (pRow[firstRow].WinType != EVT_LOSER)
		{
			int32 freeSpinsNote = 100;
			int32 freeSpinsMultiplier = 1;

			// If we are in free spins mode and the prize includes a dragon one, apply multiplier/note
			if ( getGameModeId() == MODE_FREE_SPIN )
			{
				if (pRow[firstRow].Icon == ICON_DRAGON1)
				{
					freeSpinsNote = m_subGame->getData(SGDIDX_PIC1_RACE_POSITION);
					freeSpinsMultiplier = m_subGame->getData(SGDIDX_PIC1_MULTIPLIER);
				}
				else if (pRow[firstRow].Icon == ICON_DRAGON2)
				{
					freeSpinsNote = m_subGame->getData(SGDIDX_PIC2_RACE_POSITION);
					freeSpinsMultiplier = m_subGame->getData(SGDIDX_PIC2_MULTIPLIER);					
				}
				else if (pRow[firstRow].Icon == ICON_DRAGON3)
				{
					freeSpinsNote = m_subGame->getData(SGDIDX_PIC3_RACE_POSITION);
					freeSpinsMultiplier = m_subGame->getData(SGDIDX_PIC3_MULTIPLIER);
				}
			}

			// Add payout as a scatter
			int32 nPayout = getPayout( pRow[firstRow].WinType )->payoutAmount * freeSpinsMultiplier;

			increaseTotalWin( nPayout * pRow[firstRow].Multiplier * (getBetPerLine()/minimumBetTCD) );

			SlotScatter* pScatter = spin->addScatter( pRow[firstRow].Positions,
				nPayout * (getBetPerLine()/minimumBetTCD), pRow[firstRow].Multiplier, false, pRow[firstRow].WinType, 0 );

			if (freeSpinsNote != 100)
			{
				pScatter->addNote( freeSpinsNote );
			}
		}
	}

	// If we are in free spins mode, calculate race values (dragons positions and multipliers)
	if ( getGameModeId() == MODE_FREE_SPIN )
	{
		evaluateFreeSpinsRace(spin);
	}

	// If this is the last free spin, we have to add a win with the race position
	if ( getGameModeId() == MODE_FREE_SPIN && getFreeSpins() == 1)
	{
		evaluateFreeSpinsEndRace( spin );	
	}
}

/////////////////////////////////////////////////////////////////////////////////////////////
/// @fn 	 TeaCupDragonGuts::evaluateFreeSpinsEndRace( )
///
/// This method is used to store calculate the amount won by the user according to the
/// race position of the dragon he chose
/////////////////////////////////////////////////////////////////////////////////////////////
void TeaCupDragonGuts::evaluateFreeSpinsEndRace( SlotSpin* spin )
{
	int32 racePosition = 0;
	int32 amountWon, winType;
	
	// We get the position of the dragon which was chosen by the user at the beginning of the free spins
	int userDragon = m_subGame->getData(SGDIDX_USER_DRAGON);
	switch(userDragon)
	{
		case ICON_DRAGON1:	racePosition = m_subGame->getData(SGDIDX_PIC1_RACE_POSITION);
							break;
		case ICON_DRAGON2:	racePosition = m_subGame->getData(SGDIDX_PIC2_RACE_POSITION);
							break;
		case ICON_DRAGON3:	racePosition = m_subGame->getData(SGDIDX_PIC3_RACE_POSITION);
							break;
	}

	// According to that position, calculate payout: 1st->125 cents; 2nd->75 cents; 3rd->25 cents
	if (racePosition == NOTE_FREE_SPINS_THIRD)
	{
		amountWon = 25 * (getBetPerLine()/minimumBetTCD);
		winType = EVT_THIRD_PLACE;  
	}
	else if (racePosition == NOTE_FREE_SPINS_SECOND || racePosition == NOTE_FREE_SPINS_TIED_SECOND)
	{
		amountWon = 75 * (getBetPerLine()/minimumBetTCD);
		winType = EVT_SECOND_PLACE;
	}
	else
	{
		amountWon = 125 * (getBetPerLine()/minimumBetTCD);
		winType = EVT_FIRST_PLACE;
	}

	// Add the prize
	spin->addScatter( 0, amountWon, 1, false, winType, 0 );
}

/////////////////////////////////////////////////////////////////////////////////////////////
/// @fn 	 TeaCupDragonGuts::evaluateFreeSpinsRace( SlotSpin* spin )
///
/// This method is used to store calculate dragons counts and positions in a free spins race
/////////////////////////////////////////////////////////////////////////////////////////////
void TeaCupDragonGuts::evaluateFreeSpinsRace( SlotSpin* spin )
{
	int32 dragon1_count = m_subGame->getData(SGDIDX_PIC1_COUNT);
	int32 dragon2_count = m_subGame->getData(SGDIDX_PIC2_COUNT);
	int32 dragon3_count = m_subGame->getData(SGDIDX_PIC3_COUNT);
	int32 dragon1_positions = 0;
	int32 dragon2_positions = 0;
	int32 dragon3_positions = 0;

	for( int reel = 0; reel < getReelCount(); reel++ )
	{
		// The position bit for the current icon in case it needs to be stored in a mask.
		uint8 position = reel;

		// Loop through each row in the wheel house.
		for( int row = 0; row < 3; row++ )
		{
			// Get the current stop.
			uint8 stop = relativeWheelPosition( getGameModeId(), reel, spin->getStops()[ reel ], row );

			// Get the icon for the current stop.
			uint8 currentIcon = getIcon( getGameModeId(), reel, stop )->iconid;
			
			// If the icon is the one we are looking for...
			if ( currentIcon == ICON_DRAGON1 )
			{
				// then increase the icon count
				dragon1_count++;

				// Set the bit in the position mask for this stop.
				dragon1_positions |= 1 << position;
			}
			else if ( currentIcon == ICON_DRAGON2 )
			{
				// then increase the icon count
				dragon2_count++;

				// Set the bit in the position mask for this stop.
				dragon2_positions |= 1 << position;
			}
			else if ( currentIcon == ICON_DRAGON3 )
			{
				// then increase the icon count
				dragon3_count++;

				// Set the bit in the position mask for this stop.
				dragon3_positions |= 1 << position;
			}

			// Move to the next bit in the position mask.
			position += 5;
		}
	}		

	// Update subgame data
	m_subGame->update(SGDIDX_PIC1_COUNT, dragon1_count);
	m_subGame->update(SGDIDX_PIC2_COUNT, dragon2_count);
	m_subGame->update(SGDIDX_PIC3_COUNT, dragon3_count);
	m_subGame->update(SGDIDX_PIC1_POSITIONS, dragon1_positions);
	m_subGame->update(SGDIDX_PIC2_POSITIONS, dragon2_positions);
	m_subGame->update(SGDIDX_PIC3_POSITIONS, dragon3_positions);

	// According to these dragons count, we calculate their position and multiplier in the race
	int32 racePositions[3];
	int32 raceCounts[3];
	racePositions[0] = ICON_DRAGON1;	raceCounts[0] = dragon1_count;
	racePositions[1] = ICON_DRAGON2;	raceCounts[1] = dragon2_count;
	racePositions[2] = ICON_DRAGON3;	raceCounts[2] = dragon3_count;
	bool8 modified = true;
	// Order positions
	while (modified)
	{
		modified = false;
		int32 auxPosition, auxCount;
		if (raceCounts[0] < raceCounts[1])
		{
			auxPosition = racePositions[0];
			auxCount = raceCounts[0];
			racePositions[0] = racePositions[1];
			raceCounts[0] = raceCounts[1];
			racePositions[1] = auxPosition;
			raceCounts[1] = auxCount;
			modified = true;
		}
		if (raceCounts[1] < raceCounts[2])
		{
			auxPosition = racePositions[1];
			auxCount = raceCounts[1];
			racePositions[1] = racePositions[2];
			raceCounts[1] = raceCounts[2];
			racePositions[2] = auxPosition;
			raceCounts[2] = auxCount;
			modified = true;
		}
	}

	// The dragons are ordered, but maybe there are ties among them
	if (raceCounts[0] > raceCounts[1])
	{
		// Icon in [0] first
		setDragonPosition(racePositions[0], NOTE_FREE_SPINS_FIRST, MULTIPLIER_FREE_SPINS_FIRST);
		if (raceCounts[1] > raceCounts[2])
		{
			// Icon in [1] second
			setDragonPosition(racePositions[1], NOTE_FREE_SPINS_SECOND, MULTIPLIER_FREE_SPINS_SECOND);
			// Icon in [2] third
			setDragonPosition(racePositions[2], NOTE_FREE_SPINS_THIRD, MULTIPLIER_FREE_SPINS_THIRD);
		}
		else
		{
			// Icons in [1][2] tied second position
			setDragonPosition(racePositions[1], NOTE_FREE_SPINS_TIED_SECOND, MULTIPLIER_FREE_SPINS_TIED_SECOND);
			setDragonPosition(racePositions[2], NOTE_FREE_SPINS_TIED_SECOND, MULTIPLIER_FREE_SPINS_TIED_SECOND);
		}
	}
	else
	{
		if (raceCounts[1] > raceCounts[2])
		{
			// Icons in [0][1] tied first position
			setDragonPosition(racePositions[0], NOTE_FREE_SPINS_TIED_FIRST, MULTIPLIER_FREE_SPINS_TIED_FIRST);
			setDragonPosition(racePositions[1], NOTE_FREE_SPINS_TIED_FIRST, MULTIPLIER_FREE_SPINS_TIED_FIRST);
			// Icon in [2] third
			setDragonPosition(racePositions[2], NOTE_FREE_SPINS_THIRD, MULTIPLIER_FREE_SPINS_THIRD);
		}
		else
		{
			// Icons in [0][1][2] tied
			setDragonPosition(racePositions[0], NOTE_FREE_SPINS_TIED_ALL, MULTIPLIER_FREE_SPINS_TIED_ALL);
			setDragonPosition(racePositions[1], NOTE_FREE_SPINS_TIED_ALL, MULTIPLIER_FREE_SPINS_TIED_ALL);
			setDragonPosition(racePositions[2], NOTE_FREE_SPINS_TIED_ALL, MULTIPLIER_FREE_SPINS_TIED_ALL);
		}
	}
}

/////////////////////////////////////////////////////////////////////////////////////////////
/// @fn 	 TeaCupDragonGuts::setDragonPosition(int32 icon, int32 position, int32 multiplier)   
///
/// This aux method is used to store subgame data (position and multiplier) for dragons
/// in a free spins race
/////////////////////////////////////////////////////////////////////////////////////////////
void TeaCupDragonGuts::setDragonPosition(int32 icon, int32 position, int32 multiplier)
{
	switch(icon)
	{
		case ICON_DRAGON1:	m_subGame->update( SGDIDX_PIC1_RACE_POSITION, position );
							m_subGame->update( SGDIDX_PIC1_MULTIPLIER, multiplier );
							break;
		case ICON_DRAGON2:	m_subGame->update( SGDIDX_PIC2_RACE_POSITION, position );
							m_subGame->update( SGDIDX_PIC2_MULTIPLIER, multiplier );
							break;
		case ICON_DRAGON3:	m_subGame->update( SGDIDX_PIC3_RACE_POSITION, position );
							m_subGame->update( SGDIDX_PIC3_MULTIPLIER, multiplier );
							break;
	}
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 TeaCupDragonGuts::isValidGuts()   
///
/// @return	 bool8      True if gut is valid.    
///
/// This helper method is used to see if the current gut ID is valid.
////////////////////////////////////////////////////////////////////////////
bool8 TeaCupDragonGuts::isValidGuts()
{
	// Make sure that the m_aScatterWinSpinResults array has an entry for each reel,
	// and an additional entry in case there are 0 icons on the line.
	ASSERT( countof( m_aScatterWinSpinResults[0] ) == getReelCount( MODE_NORMAL ) + 1 );

	// Now make sure that both game modes have the same number of reels.
	ASSERT( getReelCount( MODE_NORMAL ) == getReelCount( MODE_FREE_SPIN ) );

	// Finally just check to see if the gut is within the right range. GENESIS GAMES: [9000,9500)
    return ( getGutsId() >= 9000 && getGutsId() < 9500 );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 TeaCupDragonGuts::getGameModeMultiplierAndNoteId( uint8& nGameModeMultiplier, uint8& nNoteId )
///
/// @param   nGameModeMultiplier	The multiplier for the game mode.
/// @param   nNoteId				The note ID for the game mode.
///
/// This helper method is used to get the game mode multiplier and note ID.
////////////////////////////////////////////////////////////////////////////
void TeaCupDragonGuts::getGameModeMultiplierAndNoteId( uint8& nGameModeMultiplier,
	uint8& nNoteId )
{
	// If we are in free spin mode...
    if ( getGameModeId() == MODE_FREE_SPIN )
    {
		
    }
	// Otherwise...
    else
    {
		// just defer to the base class.
        SlotGuts::getGameModeMultiplierAndNoteId( nGameModeMultiplier, nNoteId );
    }
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 TeaCupDragonGuts::preSpinClassifyResults( SlotSpin* spin )
///
/// @param   spin       Pointer to the spin with stop data.
///
/// This method is overridden when running in debug spins mode to alter the reel stops.
////////////////////////////////////////////////////////////////////////////
void TeaCupDragonGuts::preSpinClassifyResults( SlotSpin* spin )
{
	// We only send race information to the client if we are in free spins mode
	if ( getGameModeId() == MODE_NORMAL ) 
	{
		setCustomSubgameDataServerOnly(true);
	}
	else
	{
		setCustomSubgameDataServerOnly(false);
	}

	SlotGuts::preSpinClassifyResults(spin);
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 TeaCupDragonGuts::postSpinClassifyResults( SlotSpin* spin )
///
/// @param   spin       Pointer to the spin with stop data.
///
/// This method is overridden to see if we can complete the game.
////////////////////////////////////////////////////////////////////////////
void TeaCupDragonGuts::postSpinClassifyResults( SlotSpin* spin )
{
	// If we are just about to start the free spins the game can't complete (until the user has chosen a dragon) 
	if ( m_subGame->getData(SGIDX_BONUS_GAME_STATE) == pfgTriggered )
	{
		resetFreeSpinsValues();
		setCustomSubgameDataServerOnly(false);
		setGameCanComplete( false );
	}
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 TeaCupDragonGuts::resetFreeSpinsValues()
///
/// This method is used to initialize flags for free spins feature
////////////////////////////////////////////////////////////////////////////
void TeaCupDragonGuts::resetFreeSpinsValues()
{
	m_subGame->update( SGDIDX_USER_DRAGON, 0);
	m_subGame->update( SGDIDX_PIC1_POSITIONS, 0);
	m_subGame->update( SGDIDX_PIC1_COUNT, 0);
	m_subGame->update( SGDIDX_PIC1_RACE_POSITION, NOTE_FREE_SPINS_TIED_ALL);
	m_subGame->update( SGDIDX_PIC1_MULTIPLIER, MULTIPLIER_FREE_SPINS_TIED_ALL);
	m_subGame->update( SGDIDX_PIC2_POSITIONS, 0);
	m_subGame->update( SGDIDX_PIC2_COUNT, 0);
	m_subGame->update( SGDIDX_PIC2_RACE_POSITION, NOTE_FREE_SPINS_TIED_ALL);
	m_subGame->update( SGDIDX_PIC2_MULTIPLIER, MULTIPLIER_FREE_SPINS_TIED_ALL);
	m_subGame->update( SGDIDX_PIC3_POSITIONS, 0);
	m_subGame->update( SGDIDX_PIC3_COUNT, 0);
	m_subGame->update( SGDIDX_PIC3_RACE_POSITION, NOTE_FREE_SPINS_TIED_ALL);
	m_subGame->update( SGDIDX_PIC3_MULTIPLIER, MULTIPLIER_FREE_SPINS_TIED_ALL);
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 TeaCupDragonGuts::processClientData()
///
/// @param   bonusGameType      The current type of bonus game.
/// @param   bonusDataCount     The number of integers passed from the client.
/// @param   bonusData			An array of integers passed from the client.
/// 
/// This is an override of the framework method.
/// 
////////////////////////////////////////////////////////////////////////////
bool8
TeaCupDragonGuts::processClientData( uint8 bonusGameType, int32 bonusDataCount, int32 *bonusData )
{
	// Start by assuming that we do not need to reply to this message
	bool8 bReply = false;

	// The message we are expecting from the client is a dragon (the dragon that the user thinks is going to win the race)
	// So we have to check two things: are we expecting the message? is it a dragon icon what we are receiving?
	if ( m_subGame->getData(SGIDX_BONUS_GAME_STATE) == pfgTriggered )
	{
		if (bonusDataCount == 1 && bonusData != NULL)
		{
			int32 nDragon = *bonusData;
			if (nDragon == ICON_DRAGON1 || nDragon == ICON_DRAGON2 || nDragon == ICON_DRAGON3)
			{
				m_subGame->update( SGDIDX_USER_DRAGON, nDragon ); 
				setGameCanComplete( true );
				setGameModeId( MODE_FREE_SPIN );
				m_subGame->update( SGIDX_BONUS_GAME_STATE, pfgNone );
				bReply = true;
			}
		}
	}
 	
	return bReply;
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 TeaCupDragonGuts::hasSavedGames()
///
/// @param   bool8   True/False indicating if this machine supports saved games.
///
/// This is a framework override to determine if this machine supports saved games.
////////////////////////////////////////////////////////////////////////////
bool8 TeaCupDragonGuts::hasSavedGames()
{
	// We support saved games so always return true.
	return true;
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 TeaCupDragonGuts::Debug_SetLoserStops( uint8* pStops )
///
/// @param   pStops		The stops to set.
///
/// Base class override, returns a losing spin triggered by the debug tool
////////////////////////////////////////////////////////////////////////////
void TeaCupDragonGuts::Debug_SetLoserStops( uint8* pStops )
{
	pStops[0]=2;
	pStops[1]=2;
	pStops[2]=2;
	pStops[3]=2;
	pStops[4]=2;
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 TeaCupDragonGuts::getProgressiveValue( )
///
/// Returns current jackpot value for TeaCupDragonGuts guts
////////////////////////////////////////////////////////////////////////////
int32 TeaCupDragonGuts::getProgressiveValue()
{
   SlotsSQL *slotTracker = (SlotsSQL *) tracker;
   int32 jackpot = 0;

    if ( tracker )
    {
    	slotTracker->lock();
		slotTracker->getJackpot(getJackpotId(), jackpot, getInfo()->forMoney, 1);
    	slotTracker->unlock();
    }

	return jackpot;
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 TeaCupDragonGuts::getProgressiveValue( )
///
/// Base class override, returns true if bonus game is in progress
///
/// In TeaCupDragonGuts we are just expecting a bonus message (user choosing a dragon) 
/// if BonusState is 1 (ptgTriggered)
/// (If BonusState is 2 the free spins feature has been 
///  retriggered, but the user does not have to choose a dragon again)
////////////////////////////////////////////////////////////////////////////
bool8 TeaCupDragonGuts::isBonusGameInProgress()
{
	int32 nBonusGameState = getBonusGameState();

	return (bool8)( nBonusGameState == pfgTriggered );
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 TeaCupDragonGuts::setCustomSubgameDataVisible( bool8 ServerOnly )
///
/// @param   ServerOnly       Make all custom data server only
///
////////////////////////////////////////////////////////////////////////////
void TeaCupDragonGuts::setCustomSubgameDataServerOnly( bool8 ServerOnly )
{
	m_subGame->setServerOnly(SGDIDX_USER_DRAGON, ServerOnly);
	m_subGame->setServerOnly(SGDIDX_PIC1_POSITIONS, ServerOnly);
	m_subGame->setServerOnly(SGDIDX_PIC1_COUNT, ServerOnly);
	m_subGame->setServerOnly(SGDIDX_PIC1_RACE_POSITION, ServerOnly);
	m_subGame->setServerOnly(SGDIDX_PIC1_MULTIPLIER, ServerOnly);
	m_subGame->setServerOnly(SGDIDX_PIC2_POSITIONS, ServerOnly);
	m_subGame->setServerOnly(SGDIDX_PIC2_COUNT, ServerOnly);
	m_subGame->setServerOnly(SGDIDX_PIC2_RACE_POSITION, ServerOnly);
	m_subGame->setServerOnly(SGDIDX_PIC2_MULTIPLIER, ServerOnly);
	m_subGame->setServerOnly(SGDIDX_PIC3_POSITIONS, ServerOnly);
	m_subGame->setServerOnly(SGDIDX_PIC3_COUNT, ServerOnly);
	m_subGame->setServerOnly(SGDIDX_PIC3_RACE_POSITION, ServerOnly);
	m_subGame->setServerOnly(SGDIDX_PIC3_MULTIPLIER, ServerOnly);
}